package com.winshare.saleAssistant.service.impl;

import com.winshare.saleAssistant.constant.RoleType;
import com.winshare.saleAssistant.dao.StaffMapper;
import com.winshare.saleAssistant.dao.StaffRoleMapper;
import com.winshare.saleAssistant.domain.dto.resp.*;
import com.winshare.saleAssistant.domain.entity.*;
import com.winshare.saleAssistant.domain.query.StaffExcelExportQuery;
import com.winshare.saleAssistant.domain.query.StaffQuery;
import com.winshare.saleAssistant.domain.dto.req.*;
import com.winshare.saleAssistant.exception.BusinessException;
import com.winshare.saleAssistant.mapper.StaffMapStruct;
import com.winshare.saleAssistant.service.RedisService;
import com.winshare.saleAssistant.service.SmsService;
import com.winshare.saleAssistant.service.StaffService;
import com.winshare.saleAssistant.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class StaffServiceImpl implements StaffService {

    private final static Logger logger = LoggerFactory.getLogger(StaffServiceImpl.class);

    private final static String INITIAL_PASSWORD = "123456";

    private final StaffMapper staffMapper;

    private final StaffRoleMapper staffRoleMapper;

    private final RedisService redisService;

    private final SmsService smsService;

    public StaffServiceImpl(StaffMapper staffMapper, StaffRoleMapper staffRoleMapper,
                            RedisService redisService, SmsService smsService) {
        this.staffMapper = staffMapper;
        this.staffRoleMapper = staffRoleMapper;
        this.redisService = redisService;
        this.smsService = smsService;
    }

    @Override
    public void save(StaffCreateDTO staffCreateDTO) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromStaffCreateDTO(staffCreateDTO);
        if (checkAccountExist(staffDO)) {
            throw new BusinessException("当前职员所用的账号在系统中已存在：" + staffCreateDTO.getAccount());
        }
        if (checkPhoneExist(staffDO)) {
            throw new BusinessException("当前职员所用的手机号码在系统中已存在：" + staffCreateDTO.getPhone());
        }
        staffDO.setSalt(SaltUtils.next());
        staffDO.setPassword(INITIAL_PASSWORD);
        staffDO.setPassword(PwdHashUtils.hash(staffDO.getPassword(), staffDO.getCredentialsSalt()));
        staffMapper.saveStaff(staffDO);
        StaffDO staffInSql = staffMapper.queryByStaff(staffDO);
        List<RoleDO> roleDOList = staffDO.getRoleList();
        if (!CollectionUtils.isEmpty(roleDOList)) {
            List<RoleStaffDO> roleStaffDOList = roleDOList.stream().map(item -> {
                RoleStaffDO roleStaffDO = new RoleStaffDO();
                roleStaffDO.setRoleId(item.getId());
                roleStaffDO.setStaffId(staffInSql.getId());
                return roleStaffDO;
            }).collect(Collectors.toList());
            staffRoleMapper.batchInsertStaffRole(roleStaffDOList);
            StaffDO staffDO1 = new StaffDO();
            staffDO1.setId(staffInSql.getId());
            staffDO1.setRole(roleDOList.stream().map(item -> item.getRoleName()).collect(Collectors.joining(",")));
            staffMapper.updateStaff(staffDO1);
        }
        List<AppRoleDO> appRoleDOList = staffDO.getAppRoleList();
        if (!CollectionUtils.isEmpty(appRoleDOList)) {
            List<AppRoleStaffDO> appRoleStaffDOList = appRoleDOList.stream().map(item -> {
                AppRoleStaffDO appRoleStaffDO = new AppRoleStaffDO();
                appRoleStaffDO.setAppRoleId(item.getId());
                appRoleStaffDO.setStaffId(staffInSql.getId());
                return appRoleStaffDO;
            }).collect(Collectors.toList());
            staffRoleMapper.batchInsertStaffAppRole(appRoleStaffDOList);
            StaffDO staffDO1 = new StaffDO();
            staffDO1.setId(staffInSql.getId());
            staffDO1.setAppRole(appRoleDOList.stream().map(item -> item.getRoleName()).collect(Collectors.joining(",")));
            staffMapper.updateStaff(staffDO1);
        }
    }

    @Override
    public void update(StaffUpdateDTO staffUpdateDTO) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromStaffUpdateDTO(staffUpdateDTO);
        if (!CollectionUtils.isEmpty(staffDO.getRoleList())) {
            if (staffDO.getId() == 2 || staffDO.getId() == 1) {
                throw new BusinessException("超级管理员的账号不能随意更改其角色！");
            }
        }
        if (checkAccountExist(staffDO)) {
            throw new BusinessException("当前职员所用的账号在系统中已存在");
        }
        if (checkPhoneExist(staffDO)) {
            throw new BusinessException("当前职员所用的手机号码在系统中已存在");
        }
        staffMapper.updateStaff(staffDO);
        List<RoleDO> roleDOList = staffDO.getRoleList();
        if (!CollectionUtils.isEmpty(roleDOList)) {
            staffRoleMapper.deleteAllRoleByStaffId(staffDO);
            List<RoleStaffDO> roleStaffDOList = roleDOList.stream().map(item -> {
                RoleStaffDO roleStaffDO = new RoleStaffDO();
                roleStaffDO.setRoleId(item.getId());
                roleStaffDO.setStaffId(staffDO.getId());
                return roleStaffDO;
            }).collect(Collectors.toList());
            staffRoleMapper.batchInsertStaffRole(roleStaffDOList);
            StaffDO staffDO1 = new StaffDO();
            staffDO1.setId(staffDO.getId());
            staffDO1.setRole(roleDOList.stream().map(item -> item.getRoleName()).collect(Collectors.joining(",")));
            staffMapper.updateStaff(staffDO1);
        }
        List<AppRoleDO> appRoleDOList = staffDO.getAppRoleList();
        if (!CollectionUtils.isEmpty(appRoleDOList)) {
            staffRoleMapper.deleteAllAppRoleByStaffId(staffDO);
            List<AppRoleStaffDO> appRoleStaffDOList = appRoleDOList.stream().map(item -> {
                AppRoleStaffDO appRoleStaffDO = new AppRoleStaffDO();
                appRoleStaffDO.setAppRoleId(item.getId());
                appRoleStaffDO.setStaffId(staffDO.getId());
                return appRoleStaffDO;
            }).collect(Collectors.toList());
            staffRoleMapper.batchInsertStaffAppRole(appRoleStaffDOList);
            StaffDO staffDO1 = new StaffDO();
            staffDO1.setId(staffDO.getId());
            staffDO1.setAppRole(appRoleDOList.stream().map(item -> item.getRoleName()).collect(Collectors.joining(",")));
            staffMapper.updateStaff(staffDO1);
        }
    }

    @Override
    public void delete(StaffDeleteDTO staffDeleteDTO) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromStaffDeleteDTO(staffDeleteDTO);
        if (staffDO.getId() == 2 || staffDO.getId() == 1) {
            throw new BusinessException("超级管理员的账号不能随意删除！");
        }
        List<RoleDO> roleDOList = staffDO.getRoleList();
        if (!CollectionUtils.isEmpty(roleDOList)) {
            roleDOList.forEach(item -> {
                RoleStaffDO roleStaffDO = new RoleStaffDO();
                roleStaffDO.setStaffId(staffDO.getId());
                roleStaffDO.setRoleId(item.getId());
                staffRoleMapper.deleteRoleStaff(roleStaffDO);
            });
        }
        staffMapper.deleteStaff(staffDO);
    }

    @Override
    public Page<StaffRespDTO> getStaffList(StaffQueryDTO staffQueryDTO) {
        StaffQuery staffQuery = StaffMapStruct.INSTANCE.fromStaffQueryDTO(staffQueryDTO);
        staffQuery.setOffsetIndex(staffQuery.getOffsetIndex());
        int totalCount = staffMapper.queryStaffCount(staffQuery);
        Integer pageIndex = staffQueryDTO.getPageIndex();
        Integer pageSize = staffQueryDTO.getPageSize();
        if (0 == totalCount) {
            return new Page<>(pageIndex, pageSize, totalCount, new ArrayList<>());
        }
        List<StaffDO> staffDOList = staffMapper.findStaffListByConditions(staffQuery);
        if (Objects.equals(staffQuery.getRoleType().intValue(), RoleType.normal_role)) {
            staffDOList.forEach(item -> {
                List<RoleDO> roleList = staffMapper.queryRoleListByStaff(item);
                if (!CollectionUtils.isEmpty(roleList)) {
                    item.setRoleList(roleList);
                }
            });
        }
        if (Objects.equals(staffQuery.getRoleType().intValue(), RoleType.app_role)) {
            staffDOList.forEach(item -> {
                List<AppRoleDO> appRoleList = staffMapper.queryAppRoleListByStaff(item);
                if (!CollectionUtils.isEmpty(appRoleList)) {
                    item.setAppRoleList(appRoleList);
                }
            });
        }

        List<StaffRespDTO> staffRespDTOList =
                StaffMapStruct.INSTANCE.toStaffRespDTOList(staffDOList);
        return new Page<>(pageIndex, pageSize, totalCount, staffRespDTOList);
    }

    @Override
    public UserRespDTO login(LoginDTO loginDTO, HttpServletRequest request, HttpSession session) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromLoginDTO(loginDTO);
        staffDO.setPassword(null);
        StaffDO staffDOInSql = staffMapper.queryByStaff(staffDO);
        if (staffDOInSql == null) {
            throw new BusinessException("当前用户不存在");
        } else if (!PwdHashUtils.hash(loginDTO.getPassword(),
                staffDOInSql.getCredentialsSalt()).equals(staffDOInSql.getPassword())) {
            throw new BusinessException("当前用户或密码错误");
        } else {
            String token = staffDOInSql.getSalt();
            redisService.setCurrentUserInfo(token, staffDOInSql, 3600);
            StaffDO staffDO1 = new StaffDO();
            staffDO1.setId(staffDOInSql.getId());
            staffDO1.setLastLoginTime(LocalDateTime.now().toString());
            staffMapper.updateStaff(staffDO1);
            UserRespDTO userRespDTO = new UserRespDTO();
            userRespDTO.setToken(token);
            return userRespDTO;
        }
    }

    @Override
    public void getVerificationCode(CaptchaReqDTO captchaReqDTO) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromCaptchaReqDTO(captchaReqDTO);
        StaffDO staffDOInSql = staffMapper.queryByStaff(staffDO);
        if (null == staffDOInSql) {
            throw new BusinessException("该账号在系统中不存在,请联系系统管理员");
        }
        // 生成短信验证码、并发送短信
        String captchaCode = CaptchaUtils.getCaptchaCode();
        redisService.putCaptchaCode(staffDO.getPhone(), captchaCode);
        smsService.sendSms(captchaCode, staffDO.getPhone());
    }

    @Override
    public UserRespDTO loginByPhone(LoginByPhoneDTO loginByPhoneDTO, HttpServletRequest request) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromLoginByPhoneDTO(loginByPhoneDTO);
        String captchaCode = redisService.getCaptchaCode(loginByPhoneDTO.getPhone());
        logger.info("手机{}验证码：{}验证码：{}", loginByPhoneDTO.getPhone(), captchaCode, loginByPhoneDTO.getCaptchaCode());
        if (Objects.equals(captchaCode, loginByPhoneDTO.getCaptchaCode())) {
            redisService.expireCaptchaCode(loginByPhoneDTO.getPhone());
        } else {
            throw new BusinessException("验证码错误");
        }
        staffDO.setOpenId(null);
        StaffDO staffDOInSql = staffMapper.queryByStaff(staffDO);
        if (null == staffDOInSql) {
            throw new BusinessException("当前用户不存在");
        }
        if (!StringUtils.isEmpty(loginByPhoneDTO.getOpenId())) {
            StaffDO staffDO1 = new StaffDO();
            staffDO1.setOpenId(loginByPhoneDTO.getOpenId());
            staffDO1.setId(staffDOInSql.getId());
            staffMapper.updateStaff(staffDO1);
            staffDOInSql.setOpenId(loginByPhoneDTO.getOpenId());
        }
        redisService.setCurrentUserInfo(staffDOInSql.getSalt(), staffDOInSql, 3600);

        StaffDO staffDO1 = new StaffDO();
        staffDO1.setId(staffDOInSql.getId());
        if (staffDOInSql.getActiveTime() == null) {
            staffDO1.setActiveTime(LocalDateTime.now().toString());
        }
        staffDO1.setLastLoginTime(LocalDateTime.now().toString());
        staffMapper.updateStaff(staffDO1);

        UserRespDTO userRespDTO = new UserRespDTO();
        userRespDTO.setToken(staffDOInSql.getSalt());
        return userRespDTO;
    }

    @Override
    public List<MenuDTO> getMenuListByCurrent(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (null == token) {
            throw new BusinessException("请求不合法,请传入token");
        }
        StaffDO staffDO = RequestHolder.getCurrentUser();
        if (null == staffDO) {
            throw new BusinessException("登录时间已过期,请重新登录!");
        }
        List<MenuDO> menuDOList = staffMapper.getMenuListByPerson(staffDO);
        List<MenuDTO> menuDTOList = StaffMapStruct.INSTANCE.fromMenuDOList(menuDOList);
        return menuDTOList;
    }

    @Override
    public void setStudyModel(StudyModelDTO studyModelDTO, HttpServletRequest request) {
        String token = request.getHeader("token");
        if (null == token) {
            throw new BusinessException("请求不合法,请传入token");
        }
        StaffDO staffDO1 = RequestHolder.getCurrentUser();
        if (null == staffDO1) {
            throw new BusinessException("登录时间已过期,请重新登录!");
        }
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromStudyModelDTO(studyModelDTO);
        staffDO.setId(staffDO1.getId());
        staffDO.setIsChangeModel(1);
        staffMapper.updateStaff(staffDO);
    }

    @Override
    public void setSubscribeModel(SubscribeModelDTO subscribeModelDTO, HttpServletRequest request) {
        String token = request.getHeader("token");
        if (null == token) {
            throw new BusinessException("请求不合法,请传入token");
        }
        StaffDO staffDO1 = RequestHolder.getCurrentUser();
        if (null == staffDO1) {
            throw new BusinessException("登录时间已过期,请重新登录!");
        }
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromSubscribeModelDTO(subscribeModelDTO);
        staffDO.setId(staffDO1.getId());
        staffDO.setIsChangeModel(1);
        staffMapper.updateStaff(staffDO);
    }

    @Override
    public void loginOut(HttpServletRequest request) {
        request.getSession().removeAttribute(request.getHeader("token"));
    }

    @Override
    public void setPhone(PhoneChangeDTO phoneChangeDTO, HttpServletRequest request) {
        String token = request.getHeader("token");
        if (null == token) {
            throw new BusinessException("请求不合法,请传入token");
        }
        ;
        StaffDO staffSession = RequestHolder.getCurrentUser();
        if (null == staffSession) {
            throw new BusinessException("登录时间已过期,请重新登录!");
        }

//        if(Objects.equals(staffSession.getPhone(),phoneChangeDTO.getPhone())) {
//            throw new BusinessException("现在的手机号与原来的手机号相同，请确认后再变更");
//        }
        if (!Objects.equals(redisService.getCaptchaCode(phoneChangeDTO.getPhone()), phoneChangeDTO.getCaptchaImage())) {
            throw new BusinessException("验证码错误");
        }
        redisService.expireCaptchaCode(phoneChangeDTO.getPhone());
        StaffDO staffQuery = new StaffDO();
        staffQuery.setPhone(phoneChangeDTO.getPhone());
        StaffDO staffDOInSql = staffMapper.queryByStaff(staffQuery);
        if (null != staffDOInSql) {
            throw new BusinessException("该手机号已被人注册");
        }
        StaffDO staffDO = new StaffDO();
        staffDO.setId(staffSession.getId());
        staffDO.setPhone(phoneChangeDTO.getPhone());
        staffMapper.updateStaff(staffDO);
    }

    @Override
    public Object loginByOpenId(LoginByOpenIdDTO loginByOpenIdDTO, HttpServletRequest request) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromLoginByOpenIdDTO(loginByOpenIdDTO);
        StaffDO staffDOInSql = staffMapper.queryByStaff(staffDO);
        if (staffDOInSql == null) {
            throw new BusinessException("当前用户不存在");
        } else {
            redisService.setCurrentUserInfo(staffDOInSql.getSalt(), staffDOInSql, 3600);

            StaffDO staffDO1 = new StaffDO();
            staffDO1.setId(staffDOInSql.getId());
            staffDO1.setLastLoginTime(LocalDateTime.now().toString());
            staffMapper.updateStaff(staffDO1);

            UserRespDTO userRespDTO = new UserRespDTO();
            userRespDTO.setToken(staffDOInSql.getSalt());
            return userRespDTO;
        }
    }

    @Override
    public StaffRespDTO getStaffDetail(BaseIdDTO baseIdDTO) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromBaseIdDTO(baseIdDTO);
        StaffDO staffDOInSql = staffMapper.getStaff(staffDO);
        if (staffDOInSql == null) {
            throw new BusinessException("当前用户不存在");
        }
        StaffRespDTO staffRespDTO = StaffMapStruct.INSTANCE.toStaffRespDTO(staffDOInSql);
        return staffRespDTO;
    }

    @Override
    public StaffDO getStaffDetailByOpenId(StaffDO staffDO) {
        StaffDO staffDOInSql = staffMapper.queryByStaff(staffDO);
        return staffDOInSql;
    }

    @Override
    public List<AppDO> getAppListByCurrent(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (null == token) {
            throw new BusinessException("请求不合法,请传入token");
        }
        StaffDO staffDO = RequestHolder.getCurrentUser();
        if (null == staffDO) {
            throw new BusinessException("登录时间已过期,请重新登录!");
        }
        List<AppDO> appDOList = staffMapper.getAppListByPerson(staffDO);
        // List<AppDTO> appDTOList = StaffMapStruct.INSTANCE.fromAppDOList(appDOList);
        return appDOList;
    }

    @Override
    public StaffCurrentInfoDTO getCurrentStaffInfo() {
        StaffDO staffDO = RequestHolder.getCurrentUser();
        StaffDO staffDOInSql = staffMapper.getCurrentStaffInfo(staffDO);
        StaffCurrentInfoDTO staffCurrentInfoDTO = StaffMapStruct.INSTANCE.fromStaffDO(staffDOInSql);
        return staffCurrentInfoDTO;
    }

    @Override
    public void setHeadImage(HeadImageDTO headImageDTO) {
        StaffDO staffDO = RequestHolder.getCurrentUser();
        StaffDO staffDOInsert = new StaffDO();
        staffDOInsert.setImageUrl(headImageDTO.getImageUrl());
        staffDOInsert.setId(staffDO.getId());
        staffMapper.updateStaff(staffDOInsert);
    }

    @Override
    public void setProductReadPassword(SetProductReadPasswordDTO setProductReadPasswordDTO) {
        StaffDO staffDO = StaffMapStruct.INSTANCE.fromSetProductReadPasswordDTO(setProductReadPasswordDTO);
        staffDO.setId(RequestHolder.getCurrentUser().getId());
        staffMapper.updateStaff(staffDO);
    }

    @Override
    public List<StaffExcelExportData> getStaffExcelExportList(StaffExcelExportDTO staffExcelExportDTO) {
        StaffExcelExportQuery staffExcelExportQuery = StaffMapStruct.INSTANCE.fromStaffExcelExportDTO(staffExcelExportDTO);
        List<StaffExcelExportData> staffExcelExportList = staffMapper.getStaffExcelExportList(staffExcelExportQuery);
        return staffExcelExportList;
    }

    @Override
    public List<MenuDTO> getMenuListByCurrentPersonAndApp(BaseIdDTO baseIdDTO) {
        StaffDO staffDO = RequestHolder.getCurrentUser();
        if (null == staffDO) {
            throw new BusinessException("登录时间已过期,请重新登录!");
        }
        List<MenuDO> menuDOList = staffMapper.getMenuListByPerson(staffDO);
        AppMenuDO appMenuDO = new AppMenuDO();
        appMenuDO.setAppId(baseIdDTO.getId());
        List<MenuDTO> menuAppDTOList = staffMapper.getMenuListByApp(appMenuDO);
        List<MenuDTO> menuDTOList = menuAppDTOList.stream().filter(item -> menuDOList.stream()
                .anyMatch(itemChild -> itemChild.getId().intValue() == item.getId().intValue()))
                .collect(Collectors.toList());
        return menuDTOList;
    }

    @Override
    public List<MenuDTO> getMenuListByCurrentPersonAndAppV2(BaseIdDTO baseIdDTO) {
        List<MenuDTO> menuDTOList = getMenuListByCurrentPersonAndApp(baseIdDTO);
        // 转化成一棵树的形式
        if (!CollectionUtils.isEmpty(menuDTOList)) {
            List<MenuDTO> menuTreeDTOList = buildTree(menuDTOList);
            return menuTreeDTOList;
        }
        return new ArrayList<>();
    }

    @Override
    public List<MenuDTO> getMenuListByCurrentV2(HttpServletRequest request) {
        List<MenuDTO> menuDTOList = getMenuListByCurrent(request);
        // 转化成一棵树的形式
        if (!CollectionUtils.isEmpty(menuDTOList)) {
            List<MenuDTO> menuTreeDTOList = buildTree(menuDTOList);
            return menuTreeDTOList;
        }
        return new ArrayList<>();
    }

    private List<MenuDTO> buildTree(List<MenuDTO> menuDTOList) {
        List<MenuDTO> treeRespDTOList = new ArrayList<>();
        for (MenuDTO menuDTO : menuDTOList) {
            if (menuDTO.getParentMenuId().intValue() == 0) {
                menuDTO = buildChildTree(menuDTO, menuDTOList);
                treeRespDTOList.add(menuDTO);
            }
        }
        return treeRespDTOList;
    }

    private MenuDTO buildChildTree(MenuDTO pNode, List<MenuDTO> menuDTOList) {
        List<MenuDTO> childMenuDTOList = new ArrayList<>();
        for (MenuDTO menuDTO : menuDTOList) {
            if (menuDTO.getParentMenuId().intValue() == pNode.getId()) {
                childMenuDTOList.add(buildChildTree(menuDTO, menuDTOList));
            }
        }
        pNode.setChildMenuTreeDTOList(childMenuDTOList);
        return pNode;
    }

    private boolean checkAccountExist(StaffDO staffDO) {
        return staffMapper.countByAccount(staffDO) > 0;
    }

    private boolean checkPhoneExist(StaffDO staffDO) {
        return staffMapper.countByPhone(staffDO) > 0;
    }
}
